
#include "libzc.h"

// HASH function
int zc_hash(int key, int size)
{
	return (unsigned int)(key*16777619*33) % size;
}

// HASH create.
struct zc_hash_t *zc_hash_new(int hash_size, int data_size)
{
	if(hash_size <= 0 || data_size <= 0) {
		return	NULL;
	}

	// create hash struct.
	struct zc_hash_t *p = (struct zc_hash_t *)calloc(1, sizeof(struct zc_hash_t));
	if(p == NULL) {
		return NULL;
	}

	// create hash node
	p->node_array = (struct zc_hash_node_t *)calloc(hash_size, sizeof(struct zc_hash_node_t));
	if(p->node_array == NULL) {
		free(p);
		return NULL;
	}

	for(int i=0; i<hash_size; i++) {
		p->node_array[i].key = -1;
	}

	// initialation.
	p->data_size = data_size;
	p->count = 0;
	p->size = hash_size;

	return p;
}

// HASH growth.
#define HASH_GROUTH_SIZE  512
int zc_hash_growth(struct zc_hash_node_t *node)
{
	struct zc_hash_node_t *p = (struct zc_hash_node_t *)calloc(node->size + HASH_GROUTH_SIZE, sizeof(struct zc_hash_node_t));
	if(p == NULL) {
		return -1;
	}

	memcpy(p, node->node_ex, sizeof(struct zc_hash_node_t)*node->size);
	free(node->node_ex);
	node->node_ex = p;
	node->size += HASH_GROUTH_SIZE;

	return 0;
}

// HASH add s node
int zc_hash_add(struct zc_hash_t *h, int key, char *data)
{
	int idx = zc_hash(key, h->size);

	if(idx >= h->size) {
		return -1;
	}

	if(h->node_array[idx].key == -1) {
		h->node_array[idx].key = key;
		h->node_array[idx].data = data;

		h->count++;
	} else {
		if(h->node_array[idx].node_ex == NULL && h->node_array[idx].size == h->node_array[idx].count) {
			zc_hash_growth(&h->node_array[idx]);
		}
		for(int i=0; i<h->node_array[idx].count; i++) {
			if(h->node_array[idx].node_ex[i].key == key) {
				h->node_array[idx].node_ex[i].data = data;
				return 0;
			}
		}

		h->node_array[idx].node_ex[h->node_array[idx].count].key = key;
		h->node_array[idx].node_ex[h->node_array[idx].count].data = data;
		h->node_array[idx].count++;
		h->count++;
	}

	return 0;
}

// HASH del a node
int zc_hash_del(struct zc_hash_t *h, int key)
{
	int idx = zc_hash(key, h->size);

	if(idx >= h->size) {
		return -1;
	}

	if(h->node_array[idx].key == key) {
		h->node_array[idx].key = -1;
		h->count--;
		return 0;
	} else {
		for(int i=0; i<h->node_array[idx].count; i++) {
			if(h->node_array[idx].node_ex[i].key == key) {
				h->node_array[idx].node_ex[i].key = h->node_array[idx].node_ex[h->node_array[idx].count-1].key;
				h->node_array[idx].node_ex[h->node_array[idx].count-1].key = -1;
				h->node_array[idx].count--;
				h->count--;
				return 0;
			}
		}
	}

	return 0;
}

// HASH find a node.
char *zc_hash_find(struct zc_hash_t *h, int key)
{
	int idx = zc_hash(key, h->size);

	if(idx >= h->size) {
		return NULL;
	}

	if(h->node_array[idx].key == key) {
		return h->node_array[idx].data;
	} else {
		for(int i=0; i<h->node_array[idx].count; i++) {
			if(h->node_array[idx].node_ex[i].key == key) {
				return h->node_array[idx].node_ex[i].data;
			}
		}
	}

	return NULL;
}

// HASH destroy.
void zc_hash_destroy(struct zc_hash_t **hh)
{
	struct zc_hash_t *h = *hh;
	if(h == NULL) {
		return;
	}

	for(int i=0; i<h->size; i++) {
		if(h->node_array[i].node_ex != NULL) {
			free(h->node_array[i].node_ex);
		}
	}

	free(h);
	*hh = NULL;

	return;
}

// HASH status display.
void zc_hash_stat(struct zc_hash_t *h)
{
	if(h == NULL) {
		return;
	}

	printf("\n----HASH STAT----- size=[%d], count=[%d]-----\n", h->size, h->count);
	for(int i=0; i<h->size; i++) {
		printf("\t --- idx=[%d], size=[%d], count=[%d]\n", i, h->node_array[i].size, h->node_array[i].count);
		printf("\tkey=[%d], data=[%p]\n", h->node_array[i].key, h->node_array[i].data);
		for(int j=0; j<h->node_array[i].count; j++) {
			printf("\tkey=[%d], data=[%p]\n", h->node_array[i].node_ex[j].key, h->node_array[i].node_ex[j].data);
		}
	}

	return;
}


